import { TMap } from '../map'
import { LngLat } from '../entity/lngLat'
import { Point } from '../entity/point'

import { Overlay } from './overlay'
import { Icon } from './icon'
import { InfoWindow } from './infoWindow'
import { DefinedOverlayTypeEnum } from './enum'

/**
 * 图像标注的属性对象
 */
export interface MarkerOptions {
    /**
     * 图标类用来表达注记。
     * 默认设置为 `new L.Icon.Default()`
     */
    icon?: Icon;

    /**
     * 决定注记是否可被鼠标或触摸拖动
     *
     * 默认值为 `false`
     */
    draggable?: boolean;

    /**
     * 默认情况下，注记图片的叠置顺序由纬度自动设置。
     * 如果你想将某一注记放置于其他之上可用这个选项，设置一个较大的值即可，
     * 比如 `'1000'`（或是相反地设置一个较大的负值）
     *
     * 默认值为 `''`
     */
    title?: string;

    /**
     * 设置 `z-index`
     *
     * 默认值为 `0`
     */
    zIndexOffset?: number;

    /**
     * 设置透明度
     *
     * 默认值为 `1.0`
     */
    opacity?: number
}

/**
 * 图像标注事件工厂对象
 */
type MarkerEventFactory = {
    /**
     * 点击标注图标后会触发此事件
     */
    click: (event: { type: 'click', target: Marker, lnglat: LngLat, containerPoint: Point }) => void;

    /**
     * 双击标注图标后会触发此事件
     */
    dblclick: (event: { type: 'dblclick', target: Marker, lnglat: LngLat, containerPoint: Point }) => void;

    /**
     * 鼠标在标注图标上按下触发此事件
     */
    mousedown: (event: { type: 'mousedown', target: Marker, lnglat: LngLat, containerPoint: Point }) => void;

    /**
     * 鼠标在标注图标释放触发此事件
     */
    mouseup: (event: { type: 'mouseup', target: Marker, lnglat: LngLat, containerPoint: Point }) => void;

    /**
     * 鼠标离开标注图标时触发此事
     */
    mouseout: (event: { type: 'mouseout', target: Marker, lnglat: LngLat, containerPoint: Point }) => void;

    /**
     * 当鼠标进入标注图标区域时会触发此事件
     */
    mouseover: (event: { type: 'mouseover', target: Marker, lnglat: LngLat, containerPoint: Point }) => void;

    /**
     * 当用户拖动标注图标时触发
     */
    dragstart: (event: { type: 'dragstart', target: Marker, lnglat: LngLat }) => void;

    /**
     * 当用户拖动标注图标时不断触发
     */
    drag: (event: { type: 'drag', target: Marker, lnglat: LngLat }) => void;

    /**
     * 当用户停止拖动标注图标时触发
     */
    dragend: (event: { type: 'dragend', target: Marker, lnglat: LngLat }) => void;

    /**
     * 移除标注图标时触发
     */
    remove: (event: { type: 'remove', target: Marker }) => void
}

/**
 * 此类表示地图上一个图像标注
 */
export interface Marker extends Overlay {
    readonly  options: MarkerOptions;

    /**
     * 创建一个图像标注实例
     *
     * @param lnglat 标注点的地理坐标
     *
     * @param opts 标注的属性对象
     */
    new(lnglat: LngLat, opts?: MarkerOptions): Marker;

    /**
     * 叠加层类型
     */
    getType: () => DefinedOverlayTypeEnum.Marker;

    /**
     * 返回标注所在的 `map` 对象
     */
    getMap: () => TMap;

    /**
     * 返回标记显示时所使用的图标对象
     */
    getIcon: () => Icon;
    /**
     * 设置标注所用的图标对象
     */
    setIcon: (icon: Icon) => void;

    /**
     * 返回标注所在的地理位置坐标
     */
    getLngLat: () => LngLat;
    /**
     * 设置标注所在的地理位置坐标
     *
     * @param lnglat 地理位置坐标
     */
    setLngLat: (lnglat: LngLat) => void;

    /**
     * 设置 `z-index`
     *
     * @param num 大于 `1` 的整数
     */
    setZIndexOffset: (num: number) => void;

    /**
     * 开启标注拖拽功能
     */
    enableDragging: () => void;
    /**
     * 关闭标注拖拽功能
     */
    disableDragging: () => void;

    /**
     * 设置标注透明度
     *
     * @param opacity 取值范围 `0-1` 之间
     */
    setOpacity: (opacity: number) => void;

    /**
     * 打开信息窗
     *
     * @param infowin `InfoWindow` 对象
     */
    openInfoWindow: (infowin: InfoWindow) => void;
    /**
     * 关闭信息窗
     */
    closeInfoWindow: () => void;

    /**
     * 添加事件监听函数
     */
    addEventListener: <Event extends keyof MarkerEventFactory>(event: Event, handler: MarkerEventFactory[Event]) => void;
    
    /**
     * 移除事件监听函数
     */
    removeEventListener: <Event extends keyof MarkerEventFactory>(event: Event, handler: MarkerEventFactory[Event]) => void
}
